package 数据结构系列;

import java.util.HashMap;
import java.util.LinkedHashSet;

public class LFU缓存_460 {
    //key到val的映射，称之为KV表
    HashMap<Integer, Integer> keyToVal;
    //key到Freq的映射，称之为KF表
    HashMap<Integer, Integer> keyToFreq;
    //freq到key列表的映射，称之为FK表
    HashMap<Integer, LinkedHashSet<Integer>> freqToKeys;

    int minFreq;//记录最小的频次
    int cap;//记录LFU缓存的最大容量


    public LFU缓存_460(int capacity) {
        keyToVal = new HashMap<>();
        keyToFreq = new HashMap<>();
        freqToKeys = new HashMap<>();
        this.cap = capacity;
        this.minFreq = 0;//默认为0
    }

    public int get(int key) {
        if (!keyToVal.containsKey(key)) {
            return -1;
        }
        //增加key对应的freq
        increaseFreq(key);

        return keyToVal.get(key);
    }

    public void put(int key, int value) {
        if (this.cap <= 0) {
            return;
        }
        //key已存在
        if (keyToVal.containsKey(key)) {
            keyToVal.put(key, value);
            increaseFreq(key);
            return;
        }
        if (this.cap <= keyToVal.size()) {
            removeMinFreq();
        }
        keyToVal.put(key, value);
        keyToFreq.put(key, 1);
        freqToKeys.putIfAbsent(1, new LinkedHashSet<>());
        freqToKeys.get(1).add(key);
        //新插入后最小的频次，就是刚插入的这个元素的频次：1
        this.minFreq = 1;
    }

    public void removeMinFreq() {
        //freq 最小的key列表
        LinkedHashSet<Integer> keyList = freqToKeys.get(this.minFreq);
        //如果有很多freq相同小的，就淘汰最早插入的
        int deleteKey = keyList.iterator().next();
        //更新FK表
        keyList.remove(deleteKey);
        if (keyList.isEmpty()) {
            freqToKeys.remove(this.minFreq);
        }
        //更新KV、KF表
        keyToVal.remove(deleteKey);
        keyToFreq.remove(deleteKey);
    }

    public void increaseFreq(int key) {
        int freq = keyToFreq.get(key);
        //更新KF表
        keyToFreq.put(key, freq + 1);
        //更新FK表
        //将key从freq对应的列表删除
        freqToKeys.get(freq).remove(key);
        //将其添加到freq+1的对应列表中
        freqToKeys.putIfAbsent(freq + 1, new LinkedHashSet<>());
        freqToKeys.get(freq + 1).add(key);

        //如果freq列表空了，就移除这个freq
        if (freqToKeys.get(freq).isEmpty()) {
            freqToKeys.remove(freq);
            //如果这个freq恰好是minFreq，就更新minFreq,因为最小的freq没有对应元素了，已经被删除了，所以minFreq要加1
            if (freq == this.minFreq) {
                this.minFreq++;
            }
        }

    }
}
